import typing

from validr import T, modelclass

from .validator import compiler


@modelclass(compiler=compiler, immutable=True)
class ConfigModel:
    """Config Model"""


class WebuiConfig(ConfigModel):
    host: str = T.str
    port: int = T.int.min(0)
    webhook_port: int = T.int.min(0)
    subpath: str = T.str
    webhook_url_prefix: str = T.str.optional
    basic_auth: typing.Dict[str, str] = T.dict(
        username=T.str,
        password=T.str,
    ).optional
    threads: int = T.int.min(5)
    access_logfile: str = T.str
    error_logfile: str = T.str


class ServerConfig(ConfigModel):
    name: str = T.str
    label: typing.List[str] = T.list(T.str).optional
    host: str = T.str
    port: int = T.int.min(0)
    user: str = T.str
    password: str = T.str.optional
    private_key: str = T.path.optional
    timeout: float = T.float.min(0)


class DockerConfig(ConfigModel):
    name: str = T.str
    label: typing.List[str] = T.list(T.str).optional
    host: str = T.str
    tls: bool = T.bool.optional
    tlscacert: str = T.path.optional
    tlscert: str = T.path.optional
    tlskey: str = T.path.optional
    tlsverify: bool = T.bool.optional
    timeout: float = T.float.min(0)


class TaskTargetConfig(ConfigModel):
    type: str = T.str
    name: str = T.str
    image: str = T.str.optional


class TaskStepConfig(ConfigModel):
    lineno = T.int
    source: str = T.str
    command: str = T.str
    targets: typing.List[TaskTargetConfig] = T.list(T.model(TaskTargetConfig))
    params: dict = T.dict


class TaskConfig(ConfigModel):
    name: str = T.str
    script: str = T.str.optional
    script_file: str = T.path.optional
    notifier = T.list(T.str)
    timeout: float = T.float.min(0)
    steps: typing.List[TaskStepConfig] = T.list(T.model(TaskStepConfig))


class TimerConfig(ConfigModel):
    name: str = T.str
    task: str = T.str
    timer: str = T.timer


class WebhookConfig(ConfigModel):
    name: str = T.str
    task: str = T.str
    secret: str = T.str


class GroupNotifierConfig(ConfigModel):
    type: str = T.str.default('group')
    name: str = T.str
    group: typing.List[str] = T.list(T.str).optional


class SmtpNotifierConfig(ConfigModel):
    type: str = T.str.default('smtp')
    name: str = T.str
    host: str = T.str
    port: int = T.int.min(0)
    use_ssl: bool = T.bool
    username: str = T.str
    password: str = T.str
    receivers: typing.List[str] = T.list(T.email).minlen(1)
    timeout: float = T.float.min(0)


class ServerChanNotifierConfig(ConfigModel):
    type: str = T.str.default('server_chan')
    name: str = T.str
    endpoint: str = T.str
    sckey: str = T.str
    timeout: float = T.float.min(0)


NotifierConfig = compiler.compile(T.union(
    group=T.model(GroupNotifierConfig),
    smtp=T.model(SmtpNotifierConfig),
    server_chan=T.model(ServerChanNotifierConfig),
).by('type'))


class AlerterConfig(ConfigModel):
    secret: str = T.str
    notifier: typing.List[str] = T.list(T.str)
